<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>研究项目目录结构 | 阿力木·达依木|Alimu Dayimu</title>
    <link rel="stylesheet" href="https://alim.gitee.io/css/style.css" />
    <link rel="stylesheet" href="https://alim.gitee.io/css/fonts.css" />
    
<link href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.6.0/build/styles/github.min.css" rel="stylesheet">


    


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css" integrity="sha384-Xi8rHCmBmhbuyyhbI88391ZKP2dmfnOl4rT9ZfRI7mLTdk1wblIUnrIq35nqwEvC" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js" integrity="sha384-X/XCfMm41VSsqRNQgDerQczD69XqmjOOOwYQvr/uuC+j4OPoNhVgjdGFwhvN02Ja" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          
          
          delimiters: [
          {left: "$$", right: "$$", display: true},
          {left: "$", right: "$", display: false},
          {left: "\\(", right: "\\)", display: false},
          {left: "\\[", right: "\\]", display: true},
          {left: "\\begin{equation}", right: "\\end{equation}", display: true},
          {left: "\\begin{align}", right: "\\end{align}", display: true},
          {left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
          {left: "\\begin{gather}", right: "\\end{gather}", display: true},
          {left: "\\begin{CD}", right: "\\end{CD}", display: true},
          {left: "\\[", right: "\\]", display: true}
          ],
          
          throwOnError : false
        });
    });
</script>


  </head>

  <body>
    <nav>
    <ul class="menu">
      
      <li><a href="https://alim.gitee.io/">Home</a></li>
      
      <li><a href="https://alim.gitee.io/post/">Post</a></li>
      
      <li><a href="https://alim.gitee.io/talks/">Talks</a></li>
      
      <li><a href="https://alim.gitee.io/about/">About</a></li>
      
    </ul>
    <hr/>
    </nav>

<div class="article-meta">
<h1 class="title">研究项目目录结构</h1>
<div class="meta">
<span class="author">Alimu Dayimu</span>
<span class="date middot">2022/05/11</span>

<span class="reading-time middot"> 2 min read </span>
<div class="terms">
  
  
  
  
  
</div>
</div>
</div>




<main>
<p>很多时候我们存放项目文件时随便起一个文件夹放进，没有形成一个很好的文件存放习惯，以及文件命名习惯，导致一段时间以后不知道文件放在哪里，与他人进行协作或将项目进行转手时，因文件的混乱导致协作困难或交接失败。下面是我自己存放文件以及构建文件夹时的一些规则，这个规则主要是与数据分析和文章撰写相关的内容。这里面同时包含了版本控制，文件及文件夹整理和与他人协作方面的内容，最后提供了<code>R</code>代码快速建立项目文件夹，这些都是可重复性研究的基础。</p>
<h2 id="项目名称">项目名称</h2>
<p>一般情况下，我们会将所有的项目保存在某一个文件夹下面，比如<code>projects</code>。这个项目文件夹可能根据性质的不同，可以选择以<code>project_outsource</code>，<code>project_research</code>和<code>project_2022</code>等命名，或者将<code>project</code>进一步简写为<code>prj</code>。而后在这个大的项目文件夹下面，是这个类型的众多项目。然而在给项目起文件夹名称的时候，我们需要选择有极高的辨识度的项目文件夹名称。比如一项血脂轨迹研究的项目，可以选择<code>lipid_traj</code>，当然也可以选择<code>lipid</code>或者是<code>prj_lipid</code>当作项目文件夹名称，但是将来可能会以血脂为基础进行其他的研究，这个时候选择前者作为项目文件夹名称会更加合理。</p>
<p>项目文件夹名称需要注意的点：</p>
<ul>
<li><strong>简短</strong>：过长的文件夹名称在查看的时候不方便，而且有些时候我们会用到项目路径名称。</li>
<li><strong>唯一性</strong>：正如前面所说，文件夹名称需要唯一，同时要有区分度。如果我们有一个项目文件夹是<code>lipid</code>，而后另外一个项目文件夹是<code>lipid_traj</code>，这个时候可能会认为<code>lipid_traj</code>是项目<code>lipid</code>的一个子项目。</li>
<li><strong>辨识度</strong>：项目文件夹名称需要有足够的信息表示项目的类型和特征等，要能够通过文件夹名称对项目类猜测。</li>
</ul>
<h2 id="项目内部文件">项目内部文件</h2>
<p>下面是我自己一般情况下使用的文件和文件夹树图。</p>
<pre><code>📦lipid_traj
 ┣ 📂Data
 ┃ ┣ 📂processed
 ┃ ┗ 📂raw
 ┣ 📂Docs
 ┣ 📂Manuscript
 ┃ ┣ 📂Archives
 ┃ ┗ 📂Journal1
 ┣ 📂Notes
 ┣ 📂Output
 ┃ ┣ 📂Figures
 ┃ ┗ 📂Tables
 ┣ 📂Progs
 ┃ ┣ 📜01-import-data.R
 ┃ ┣ 📜02-clean-data.R
 ┃ ┣ 📜03-descriptives.R
 ┃ ┣ 📜04-modelling.R
 ┃ ┗ 📜helper.R
 ┣ 📂Ref
 ┣ 📂Report
 ┣ 📜common.lnk
 ┗ 📜README.txt
</code></pre>
<h3 id="data">Data</h3>
<p>这个文件夹用来存放数据文件，其中<code>raw</code>是用来存放原始数据的。注意，一定<strong>不要对原始数据进行写入操作</strong>，不要修改你的原始数据。如果这个数据时从别人那边收到的，建议让他人用邮件发送，并把沟通邮件保存在这个文件夹中。保存原始数据沟通记录的原因是保证这一步交接的责任主体，比如可能存在数据发送错误或者是数据分析错误，这两种情形的责任主体是不一样的。<strong>保存原始数据的完整性</strong>是保护你自己的最重要证据，无论是将来文章审查或者是有人对你的结果提出异议，所以再次提醒<strong>不要对原始数据进行写入操作</strong>。在分析过程中可能会产生一些中间数据或者是清理好以后的数据可以保存在<code>processed</code>子目录下面，这样能保证原始数据不被进行写入操作。<em>提醒，不要用Excel存储数据</em>，因为Excel会对里面存储的数值型字符进行格式化，比如长数字将被按照科学计数法进行保存，你将会丢失数据。</p>
<h3 id="docs">Docs</h3>
<p>这个文件夹可以用来存放与项目相关的文档，比如CRF文件，研究计划以及分析方案等。</p>
<h3 id="manuscript">Manuscript</h3>
<p>用来保存写好的文章或者是与文章相关的内容，根目录下面可以存放中间写好的文章以及文章用到的图表等，文件命名应该按照<code>manuscript-20220511.docx</code>这种格式命名，没更新一次的时候产生一个新的文件版本，把已经不需要的老的版本放到<code>Archives</code>里面进行归档。而后，在发表文章时新建以目标杂志名字命名的文件夹，把该杂志的要求以及按照该杂志进行排版好的文章放到这个文件夹里面，同时中间收到的通讯邮件等相关的内容也可以放进去。在这个以杂志名称命名的文件夹下面可以继续新建<code>1-initial-submission</code>，<code>2-first-revision</code>，<code>3-acceptance </code>等等文件夹。换一个杂志的时候再新建一个杂志名称的文件夹，直到接受为止，同时可以将之前的版本进行归档。</p>
<p>在每次新投稿的时候，包括换杂志以及文章修回，不要对原始杂志问价夹内的文章进行修改，所有的修改都应该在主文件夹下面进行，这样避免投稿时的文章状态被修改，相当于快照，投稿的时候再将文章复制到相应的文件夹里面。</p>
<h3 id="notes">Notes</h3>
<p>这个文件夹可以用来存放自己在项目过程中产生的想法，或者是记录文件。有些时候我们会其他人进行讨论，可以新建<code>minutes</code>文件夹，将会议纪要按照日期保存在这个文件夹里面。具体存放的内容可以灵活安排，包括沟通邮件或者是聊天记录也可以保存在这里，方便日后查阅沟通记录，以及回忆中间的讨论经过，防止同前面已经被排除的问题再次被拿出来讨论。也可以将该文件夹与<code>Docs</code>进行合并。在分析数据过程中可能会使用很多不同的方法进行验证，并不断地排除一些选项，这些也需要记录下来，写明自己当时验证的是什么，为什么要这么验证，怎么进行的验证，结果怎么样，以及为什么这个选项被剔除等等。</p>
<h3 id="output">Output</h3>
<p>用来保存中间生成的图片和表格，图片建议用PDF（优先）或者是PNG格式保存，同时将DPI（仅PNG）调整到300及以上。</p>
<h3 id="progs">Progs</h3>
<p>用来存放代码文件，包括<code>R</code>和<code>SAS</code>等。代码文件名称建议以数字开头，方便快速定位代码执行的顺序。一般分析步骤是<code>“读入数据--&gt;清理数据--&gt;描述数据--&gt;构建模型”</code>等，中间可能会有更多的步骤，因此代码文件前添加数字代号（比如<code>01-</code>）能让文件按步骤顺序进行排序的同时，了解代码在整个步骤中的位置。代码文件的名称需要有一定的启示性，即看到文件名就能大概了解到代码的目的。如有必要新建<code>Archives</code>文件夹，将中间过程中被新的全新版本替代的代码放到这个归档文件夹当中。如果你使用的是git版本控制系统，就没有必要使用归档文件夹了。<br>
代码文件的代码头有助于了解代码的作用，毕竟很久以后再来看代码的时候可能不知道这个文件到底时干什么的。如果想要了解代码所作的事情，需要把代码读一遍，很浪费时间，这个时候代码头有非常大的帮助。一个示例的代码头如下所示：</p>
<pre><code class="language-r">##------------------------------------------
## Project: Lipid trajectory
## Script purpose: Read and clean data
## Date: 2022-05-11
## Author: Alimu Dayimu
## Note:
##------------------------------------------
</code></pre>
<h3 id="ref">Ref</h3>
<p>可以将参考文献存放在这个文件夹下面，比如PDF文件等。有些人可能喜欢用EndNote、Citavi或者是Noteexpress等文献管理软件，这些文献管理软件可以把不同的库存放在不同的文件夹下面，即每个项目都有自己独立的文献库。这个时候可以将项目的参考文献库，一般称为library，放到这个文件下面。zotero也很好用，而且也是本人在使用的软件，虽然zotero的时候可以将library存放到这里，但是可能没有前面提到的软件那样直接打开这个目录下面的库，因为zotero只有一个总的文献库，不能在不同的地方建立不同的文献库。</p>
<h3 id="report">Report</h3>
<p>项目报告，包括汇报的PPT等放到该文件夹中。在R的可重复性研究中可以将rmd文件放到这里然后进行渲染。很多时候我们仅有一个rmd文件来渲染一个大的报告，这个rmd可能还包括分析代码，但是这样可能会导致这个rmd文件非常长，阅读起来困难。这个时候可以考虑将分析代码放在<code>Progs</code>目录中，而后将中间的分析结果以PNG格式或者是rds格式（R的数据格式）保存在<code>Output</code>中，让rmd文件仅负责报告结果。</p>
<h3 id="readmetxt">README.txt</h3>
<p>可以将项目相关的描述以及该项目文件夹里面的内容做一个简短的介绍，方便在查看这个项目文件夹时快速了解到项目的基本信息。同时可以记录一些简单的项目记录，毕竟我们不可能只有一个项目在不停的进行，需要放下这个项目一段时间。这个时候在<code>README.txt</code>里写一些关于当前最新的进度以及下一步要做什么，对于快速拾起项目很有帮助。</p>
<h3 id="common">common</h3>
<p>这个文件夹是快捷方式。虽然我们有很多不同的项目，但是有些文件是不同的项目之间可以共享的，这个时候可以将不同的项目之间共享的内容放到这个文件夹里面，而后在不同的项目中创建指向这个文件夹的快捷方式。</p>
<h2 id="协作">协作</h2>
<p>一个项目可能会有不同的人在协作，一个规范的目录结构在不同人之间的协作将会非常简单和方便，尤其是当自己你们是一个比较大的团队时，他人接手也很容易。但是有些时候我们需要跟外部协作，但是这个不影响这些文件结构。可以对其他的项目相应的文件（夹）创建快捷方式到自己的个人项目目录里面，这样在保证自己的目录没有收到影响的同时，不破坏协作项目里面的文件结构。</p>
<h2 id="版本控制">版本控制</h2>
<p>建议采用git进行版本控制，比较流行的是<a href="https://github.com/">GitHub</a>和<a href="https://gitee.com/">gitee</a>。<a href="https://rogerdudler.github.io/git-guide/index.zh.html">这里</a>有一个非常简单的指南，掌握上面的命令能满足90%以上的需求，<a href="https://ohshitgit.com/zh">这里</a>还有一些能经常遇到的问题以及一些解决办法。使用git有众多好处，除了最简单的版本控制，保留几乎所有的修改历史记录之外，还可以通过新建分支（branch）进行一些实验性的操作，如果最终这个路子通了可以将其合并（merge）到主分支（main），如果不行可以切换（<code>checkout</code>）回主分支进，实验性操作可以保留或者是删除。好处在于，这些所有的操作你都不需要新建文件夹或者是新建文件，在原来的数据上进行修改，当你切回原来的分支的时候，原来的分支不会有任何变化，所有的修改都发生在实验分支上。如果对数据的安全想有要求，可以将数据文件夹加入到<code>.gitignore</code>中，并将GitHub或者是gitee上的项目设为私人项目。对数据的安全性要求更高的，可以不需要设置线上源，用git初始化项目文件，但是不设置git源（origin），除了push和pull之外其他的功能依然可以使用，所有的操作都将会被记录在本地。</p>
<p>如果对git不是很了解，可以使用有<strong>历史版本</strong>功能的网盘，比如<a href="https://www.jianguoyun.com/">坚果云</a>或者是微软的Onedrive。坚果云普通用户有一个月的历史版本记录，如果中间出错了，可以随时对历史版本进行恢复。在国内访问速度快，推荐使用，付费版可以有三个月的历史记录，恢复三个月内的删除文件，一款良心产品。</p>
<p><img src="https://alim.gitee.io/images/2022/pub-workflow-netstore-hist.png#center" alt=""></p>
<p><strong>注意</strong>：使用网盘同步时，注意数据的<u><strong>保密</strong></u>性问题。不要将数据同步到公开访问的仓储中或目录中。不要未经加密就传输数据，可以将数据加密压缩，邮件传输，然后等对方确认以后再新发一封密码邮件或者是用短信等方式发送密码，即不同时发送密码和数据。传输数据优先使用自己单位的邮箱，让你的单位有据可查，如果有自己单位的网盘或者是内部分享途径，那就请使用这些突进进行分享。不要使用微信或QQ等方式传输数据，数据中不要包含个人的身份证号码、电话号码和住址等能够识别个人的信息，如果你收到带有这些信息的数据，可以让对方重发或者是立马删除这些信息。数据泄露超过500例要判刑的，安全第一。有些类型的数据可能会受法律监管，需要保存到国内，那么请主动放弃使用GitHub，合法合规是非常重要的。</p>
<h2 id="后记">后记</h2>
<ul>
<li>优先采用自己所在研究小组或者是部门的文件管理SOP，规范化文件命名和存储。</li>
<li>这种创建项目目录的主要目的是将文件按照一定的规律进行存放，让文件有条理。同时，有了规范的文件夹结构以后，可以编写一些通用代码，将一些事情进行自动化处理。如果所有的项目的输出文件都是<code>Output</code>以后，自编函数可以将输出结果默认到这个目录，同时这个代码可以在其他的项目中通用，提高代码的复用性。</li>
<li>文中提到的只是众多项目文件夹创建的一个可能性，这需要根据自己的习惯以及所在组的要求进行调整。在数据分析中，能够通过项目文件夹里面的内容，对最后的结果进行复现，即研究的可重复性问题。要做好文档的构建，这里的协作者不仅包括其他人，也包括将来的你。将来在你回顾你自己的项目的时候不要被自己的项目文件晕头转向，被自己恶心到。</li>
<li>给文件夹起名的时候灵活使用日期和数字前缀。</li>
<li>尽量不要使用中文来命名文件夹，有些软件在识别中文路径的时候会报错。</li>
<li>使用版本控制，<strong>注意数据安全</strong>。</li>
</ul>
<p>最后，一个项目结项以后也需要对项目进行归档，可以在项目跟目录下面创建<code>Archives</code>目录，将归档的项目保存在这个文件夹下。研究项目的规范性比创新性重要，再优秀的创新项目，垃圾的质控最后还是垃圾。</p>
<h2 id="项目文件夹生成代码">项目文件夹生成代码</h2>
<p>下面是用<code>R</code>生成主要文件夹的代码，可以根据需要自行进行修改。</p>
<pre><code class="language-r"># Name of the project
prject_name &lt;- &quot;lipid_traj&quot;

# Create project folder and change working directory
dir.create(prject_name)
setwd(prject_name)

# Set up the folder structure
folder_names &lt;- (
  # Main folders
  c(&quot;Data&quot;, &quot;Progs&quot;, &quot;Output&quot;, &quot;Report&quot;, &quot;Docs&quot;, &quot;Ref&quot;, &quot;Notes&quot;,
    &quot;Manuscript&quot;,
    # Sub-folders
    &quot;Data/raw&quot;, &quot;Data/processed&quot;, &quot;Output/Figures&quot;, &quot;Output/Tables&quot;,
    &quot;Manuscript/Archives&quot;, &quot;Manuscript/Journal1&quot;))

for (j in seq_along(folder_names)) {
  if(dir.exists(folder_names[j])) invisible(NULL)
  else dir.create(folder_names[j])
}

# Add files to the folders
file_names &lt;- (
  c(
    # For import and merging your data 
    &quot;01-import-data&quot;,
    # For data cleanning
    &quot;02-clean-data&quot;, 
    # For your descriptives
    &quot;03-descriptives&quot;,
    # For your analysis
    &quot;04-modelling&quot;
  )
)

make_r_template &lt;- function(filename = &quot;r_template.R&quot;)
{
  if (file.exists(file.path(filename))) invisible(NULL)
  else{
    write(c(&quot;##--------------------------------------&quot;,
            &quot;## Project:&quot;,
            &quot;## Script purpose:&quot;,
            paste(&quot;## Date:&quot;, format(Sys.Date(), &quot;%Y-%m-%d&quot;)),
            &quot;## Author:&quot;,
            &quot;## Note:&quot;,
            &quot;##--------------------------------------&quot;),
          file = file.path(filename),
          sep = &quot;\n&quot;)
  }
}

for (j in seq_along(file_names)) {
  f_name &lt;- paste0(&quot;Progs/&quot;, file_names[j], &quot;.R&quot;)
  make_r_template(f_name)
}

# Create a helper function file
make_r_template(&quot;Progs/helper.R&quot;)

# Create a README.txt file
file.create(&quot;README.txt&quot;)

# Create a Rstudio project file
cat(&quot;Version: 1.0&quot;, file = paste0(prject_name, &quot;.Rproj&quot;), sep = &quot;\n&quot;)

</code></pre>

</main>


  <footer>
  <script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.6.0/build/highlight.min.js"></script>
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.6.0/build/languages/r.min.js"></script>

<script>
hljs.configure({languages: []});
hljs.initHighlightingOnLoad();
</script>

  
  <hr/>
  © <a href="https://alim.gitee.io/">Alimu Dayimu</a> 2021 - 2022 | <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">BY-NC-ND 4.0</a> | <a href="https://github.com/adayim">GitHub</a> | <a href="https://gitee.com/alim">gitee</a> | <a href="https://alim.gitee.io/index.xml">RSS</a>
  
  
  </footer>
  </body>
</html>
